package com.mango.coomb.threads.controller;


import com.mango.coomb.constant.ThreadConst;
import com.mango.coomb.data.IOData;
import com.mango.coomb.enums.AreaClass;
import com.mango.coomb.enums.Sign;
import com.mango.coomb.enums.Status;
import com.mango.coomb.threads.*;
import com.mango.coomb.threads.parameter.ThreadParameter;
import com.mango.coomb.threads.parameter.util.ThreadParamUpdateUtil;
import com.mango.coomb.ui.MainJFrame;

public class ThreadControl extends Thread {
    public static final ReaderPosRead[] readerPosReadArr = new ReaderPosRead[ThreadConst.READER_POS_MAX_COUNT];
    public static final ReaderPosWrite[] readerPosWriteArr = new ReaderPosWrite[ThreadConst.READER_POS_WRITE_COUNT];
    public static final ReaderNegRead[] readerNegReadArr = new ReaderNegRead[ThreadConst.READER_NEG_MAX_COUNT];
    public static final ReaderNegWrite[] readerNegWriteArr = new ReaderNegWrite[ThreadConst.READER_NEG_WRITE_COUNT];
    public static final ReaderZeroRead[] readerZeroReadArr = new ReaderZeroRead[ThreadConst.READER_ZERO_MAX_COUNT];
    public static final ReaderZeroWrite[] readerZeroWriteArr = new ReaderZeroWrite[ThreadConst.READER_ZERO_WRITE_COUNT];
    public static final WriterRead[] writerReadArr = new WriterRead[ThreadConst.WRITER_READ_COUNT];
    public static final WriterWrite[] writerWriteArr = new WriterWrite[ThreadConst.WRITER_MAX_COUNT];
    private static final Integer[] writerBufferValueArr = ThreadParameter.getWriterBufferValueArr();
    private static final Integer[] bufferBufferValueArr = ThreadParameter.getBufferBufferValueArr();
    private static final Integer[] readerZeroBufferValueArr = ThreadParameter.getReaderZeroBufferValueArr();
    private static final Integer[] readerNegBufferValueArr = ThreadParameter.getReaderNegBufferValueArr();
    private static final Integer[] readerPosBufferValueArr = ThreadParameter.getReaderPosBufferValueArr();

//    static {
//        for (int i = 0; i < 3; i++) {
//            readerPosReadArr[i] = new ReaderPosRead();
//            readerPosWriteArr[i] = new ReaderPosWrite();
//            readerNegReadArr[i] = new ReaderNegRead();
//            readerNegWriteArr[i] = new ReaderNegWrite();
//            readerZeroReadArr[i] = new ReaderZeroRead();
//            readerZeroWriteArr[i] = new ReaderZeroWrite();
//        }
//        for (int i = 0; i < 10; i++) {
//            writerReadArr[i] = new WriterRead();
//            writerWriteArr[i] = new WriterWrite();
//        }
//    }

    @Override
    public void run() {
        while (true) {
            synchronized (ThreadControl.class) {
                switch (ThreadParameter.getOperationalStatus()) {
                    case NOT_BEGIN:
                        try {
                            Thread.sleep(1000L);
                        } catch (InterruptedException e) {
                            throw new RuntimeException(e);
                        }
                        if (ThreadParameter.startTime != null) {
                            ThreadParameter.pausedTime = System.currentTimeMillis() - ((long) (ThreadParameter.getTotalTimeSpent() * 1000) + ThreadParameter.startTime);
                        }
                        break;
                    case BEGIN:
                        startThreads();
                        break;
                    case RUNNING:
                        if (ThreadParameter.getTotalCount() == ThreadParameter.getTotalCompletionCount()
                                && ThreadParameter.isHavingData()) {
                            try {
                                Thread.sleep(1000L);
                            } catch (InterruptedException e) {
                                throw new RuntimeException(e);
                            }
                        } else {
                            runThreads();
                        }
                        break;
                    case PAUSED:
                        pauseThreads();
                        break;
                    case GO_ON:
                        goOnThreads();
                        break;
                    case END:
                        endThreads();
                        break;
                }
            }
        }
    }

    private void runThreads() {
        MainJFrame.updateThreadsImageAndData();
        MainJFrame.updateBuffersTextAndImageAndData();
        MainJFrame.updateSourceAndTargetDataText();
        int size = IOData.targetPosDataList.size();
        ThreadParamUpdateUtil.updateTargetTotalCount(size, Sign.READER_POS);
        int size1 = IOData.TargetNegDataList.size();
        ThreadParamUpdateUtil.updateTargetTotalCount(size1, Sign.READER_NEG);
        int size2 = IOData.TargetZeroDataList.size();
        ThreadParamUpdateUtil.updateTargetTotalCount(size2, Sign.READER_ZERO);
        ThreadParamUpdateUtil.updateTotalCompletionCount(size + size1 + size2);
        ThreadParamUpdateUtil.updateTotalTimeSpent((double) (System.currentTimeMillis() - ThreadParameter.startTime-ThreadParameter.pausedTime) / 1000);
        ThreadParamUpdateUtil.updateProcessingSpeedCount(ThreadParameter.getTotalCompletionCount()
                / ThreadParameter.getTotalTimeSpent());
        MainJFrame.updateSideBarText();
        try {
            sleep(100L);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    }

    private void goOnThreads() {
        ThreadParamUpdateUtil.updateIsSafe(false);
        setPaused(false);
        ThreadsNotify();
        ThreadParamUpdateUtil.updateOperationalStatus(Status.RUNNING);
    }

    private void ThreadsNotify() {
        synchronized (ThreadParameter.writerReadLock) {
            ThreadParameter.writerReadLock.notifyAll();
        }
        synchronized (ThreadParameter.writerWriteLock) {
            ThreadParameter.writerWriteLock.notifyAll();
        }
        synchronized (ThreadParameter.readerPosReadLock) {
            ThreadParameter.readerPosReadLock.notifyAll();
        }
        synchronized (ThreadParameter.readerPosWriteLock) {
            ThreadParameter.readerPosWriteLock.notifyAll();
        }
        synchronized (ThreadParameter.readerZeroReadLock) {
            ThreadParameter.readerZeroReadLock.notifyAll();
        }
        synchronized (ThreadParameter.readerZeroWriteLock) {
            ThreadParameter.readerZeroWriteLock.notifyAll();
        }
        synchronized (ThreadParameter.readerNegReadLock) {
            ThreadParameter.readerNegReadLock.notifyAll();
        }
        synchronized (ThreadParameter.readerNegWriteLock) {
            ThreadParameter.readerNegWriteLock.notifyAll();
        }
    }

    private void endThreads() {
        ThreadParameter.isWriterReadRunning = false;
        ThreadParameter.isWriterWriteRunning = false;
        ThreadParameter.isReaderPosReadRunning = false;
        ThreadParameter.isReaderPosWriteRunning = false;
        ThreadParameter.isReaderZeroReadRunning = false;
        ThreadParameter.isReaderZeroWriteRunning = false;
        ThreadParameter.isReaderNegReadRunning = false;
        ThreadParameter.isReaderNegWriteRunning = false;
        ThreadsNotify();
        ThreadParamUpdateUtil.updateOperationalStatus(Status.NOT_BEGIN);
    }

    private void pauseThreads() {
        setPaused(true);
        ThreadParamUpdateUtil.updateIsSafe(true);
        ThreadParamUpdateUtil.updateOperationalStatus(Status.NOT_BEGIN);
    }

    private static void setPaused(boolean isPaused) {
        for (int i = 0; i < ThreadConst.WRITER_READ_COUNT; i++) {
            writerReadArr[i].setPaused(isPaused);
        }
        for (int i = 0; i < ThreadParameter.getAreaCount(AreaClass.WRITER, null); i++) {
            writerWriteArr[i].setPaused(isPaused);
        }
        for (int i = 0; i < ThreadParameter.getAreaCount(AreaClass.READER, Sign.READER_POS); i++) {
            readerPosReadArr[i].setPaused(isPaused);
        }
        for (int i = 0; i < ThreadParameter.getAreaCount(AreaClass.READER, Sign.READER_NEG); i++) {

            readerNegReadArr[i].setPaused(isPaused);
        }
        for (int i = 0; i < ThreadParameter.getAreaCount(AreaClass.READER, Sign.READER_ZERO); i++) {
            readerZeroReadArr[i].setPaused(isPaused);
        }
        for (int i = 0; i < ThreadConst.READER_POS_WRITE_COUNT; i++) {
            readerPosWriteArr[i].setPaused(isPaused);
        }
        for (int i = 0; i < ThreadConst.READER_NEG_WRITE_COUNT; i++) {
            readerNegWriteArr[i].setPaused(isPaused);
        }
        for (int i = 0; i < ThreadConst.READER_ZERO_WRITE_COUNT; i++) {
            readerZeroWriteArr[i].setPaused(isPaused);
        }
    }

    private void startThreads() {
        ThreadParamUpdateUtil.updateIsSafe(false);
        ThreadParameter.isWriterReadRunning = true;
        ThreadParameter.isWriterWriteRunning = true;
        ThreadParameter.isReaderPosReadRunning = true;
        ThreadParameter.isReaderPosWriteRunning = true;
        ThreadParameter.isReaderZeroReadRunning = true;
        ThreadParameter.isReaderZeroWriteRunning = true;
        ThreadParameter.isReaderNegReadRunning = true;
        ThreadParameter.isReaderNegWriteRunning = true;
        for (int i = 0; i < ThreadConst.WRITER_READ_COUNT; i++) {
            writerReadArr[i] = new WriterRead();
            writerReadArr[i].setStatus(Status.NOT_BEGIN);
            writerReadArr[i].start();
        }
        for (int i = 0; i < ThreadParameter.getAreaCount(AreaClass.WRITER, null); i++) {
            writerWriteArr[i] = new WriterWrite();
            writerWriteArr[i].setStatus(Status.NOT_BEGIN);
            writerWriteArr[i].start();
        }
        for (int i = 0; i < ThreadParameter.getAreaCount(AreaClass.READER, Sign.READER_POS); i++) {
            readerPosReadArr[i] = new ReaderPosRead();
            readerPosReadArr[i].setStatus(Status.NOT_BEGIN);
            readerPosReadArr[i].start();
        }
        for (int i = 0; i < ThreadParameter.getAreaCount(AreaClass.READER, Sign.READER_NEG); i++) {
            readerNegReadArr[i] = new ReaderNegRead();
            readerNegReadArr[i].setStatus(Status.NOT_BEGIN);
            readerNegReadArr[i].start();
        }
        for (int i = 0; i < ThreadParameter.getAreaCount(AreaClass.READER, Sign.READER_ZERO); i++) {
            readerZeroReadArr[i] = new ReaderZeroRead();
            readerZeroReadArr[i].setStatus(Status.NOT_BEGIN);
            readerZeroReadArr[i].start();
        }
        for (int i = 0; i < ThreadConst.READER_POS_WRITE_COUNT; i++) {
            readerPosWriteArr[i] = new ReaderPosWrite();
            readerPosWriteArr[i].setStatus(Status.NOT_BEGIN);
            readerPosWriteArr[i].start();
        }
        for (int i = 0; i < ThreadConst.READER_NEG_WRITE_COUNT; i++) {
            readerNegWriteArr[i] = new ReaderNegWrite();
            readerNegWriteArr[i].setStatus(Status.NOT_BEGIN);
            readerNegWriteArr[i].start();
        }
        for (int i = 0; i < ThreadConst.READER_ZERO_WRITE_COUNT; i++) {
            readerZeroWriteArr[i] = new ReaderZeroWrite();
            readerZeroWriteArr[i].setStatus(Status.NOT_BEGIN);
            readerZeroWriteArr[i].start();
        }
        ThreadParamUpdateUtil.updateOperationalStatus(Status.RUNNING);
    }
}